package com.itheima.health.controller;

import com.itheima.health.common.MessageConst;
import com.itheima.health.common.RedisConst;
import com.itheima.health.entity.Result;
import com.itheima.health.pojo.Member;
import com.itheima.health.pojo.Role;
import com.itheima.health.security.annotation.MySecurity;
import com.itheima.health.security.common.RoleConst;
import com.itheima.health.service.MemberService;
import com.itheima.health.service.OrderService;
import com.itheima.health.service.ReportService;
import com.itheima.health.service.SetMealService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 数据报告控制器
 */
@RestController
@RequestMapping("/report")
@Slf4j
public class ReportController {
    @Autowired
    private MemberService memberService;
    @Autowired
    private ReportService reportService;
    @Autowired
    private SetMealService setMealService;

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 任务13：展示会员数量折线图
     * 分析
     * 1.查询出所有会员信息
     * 按月统计连续12个月
     * 连续12个月中，第一个月份应加上之前的所有会员数据，最后一个月份应为当前月的所有会员数据与上个月的会员总数的和。
     * 如果直接查询会员原始表进行统计花费时间较长，提前通过定时任务把会员总数按照天或月的维度把数据跑出来
     *
     * @return
     */
    @GetMapping("/getMemberReport")
    @MySecurity({RoleConst.ROLE_ADMIN,RoleConst.ROLE_DATA_READER})//管理员和数据分析师
    public Result getMemberReport() {
        log.info("查询会员信息折线图");
        //创建对象存储响应数据
        Map<String,Object> map=new HashMap<>();
        //从Redis缓存中查询会员折线图数据
        map = (Map<String, Object>) redisTemplate.opsForValue().get(RedisConst.MEMBER_REPORT);
        //如果没数据，则去数据库中查询
        if (map == null){
            map=memberService.getMemberReport();
            //查询完数据，再放到Redis中
            redisTemplate.opsForValue().set(RedisConst.MEMBER_REPORT,map);
        }
        //返回结果
        return new Result(true, MessageConst.GET_BUSINESS_REPORT_SUCCESS, map);
    }



    /**
     * 任务14：显示预约套餐占比数据
     */
    @GetMapping("/getSetmealReport")
    @MySecurity({RoleConst.ROLE_ADMIN,RoleConst.ROLE_DATA_READER})//管理员和数据分析师
    public Result getSetmealReport() {
        Map<String, Object> data = new HashMap<>();
        try {
            //查询每个套餐被预约的次数
            List<Map<String, Object>> setmealCount = setMealService.findSetmealReport();
            List<String> setmealNames = new ArrayList<>();
            //遍历数据
            for (Map<String, Object> map : setmealCount) {
                //把每个套餐的名称设置到套餐个数中
                String name = (String) map.get("name");//套餐名称
                setmealNames.add(name);
            }
            data.put("setmealNames", setmealNames);
            data.put("setmealCount", setmealCount);
            //查询成功 显示结构数据
            return new Result(true, MessageConst.GET_SETMEAL_COUNT_REPORT_SUCCESS, data);
        } catch (Exception e) {
            e.printStackTrace();
            //查询失败抛出异常
            return new Result(false, MessageConst.GET_SETMEAL_COUNT_REPORT_FAIL);
        }
    }


    /**
     * 任务15：运营数据统计页面展示
     * 将所需的数据收集到一个map集合中, 并响应给前端
     */
    @GetMapping("/getBusinessReportData")
    @MySecurity({RoleConst.ROLE_ADMIN,RoleConst.ROLE_DATA_STATIS})//管理员和数据统计员
    public Result getBusinessReportData() {
        log.info("运营数据统计 控制器层 开始执行");
        //调用自定义业务层方法, 将返回的结果封装到一个map结合中返回给前端
        Map<String, Object> reportData = reportService.getBusinessReportData();
        //将收集到的数据返回
        return new Result(true, MessageConst.GET_BUSINESS_REPORT_SUCCESS, reportData);
    }

    /**
     * 任务16：运营数据统计导出
     * 将运营数据统计报表导出到指定位置
     */
    @MySecurity({RoleConst.ROLE_ADMIN,RoleConst.ROLE_DATA_STATIS})//管理员和数据统计员
    @GetMapping("/exportBusinessReport")
    public Result exportBusinessReport(HttpServletResponse response) {
        log.info("开始导出运营数据统计报表");
        //获取运营数据的map集合, 并获取其中的具体数据
        Map<String, Object> reportData = reportService.getBusinessReportData();
        String reportDate = (String) reportData.get("reportDate");//报告日期
        Integer totalMember = (Integer) reportData.get("totalMember");//总会员数
        Integer todayNewMember = (Integer) reportData.get("todayNewMember");//今日新增会员数
        Integer thisWeekNewMember = (Integer) reportData.get("thisWeekNewMember");//本周新增会员数
        Integer thisMonthNewMember = (Integer) reportData.get("thisMonthNewMember");//本月新增会员数
        Integer todayOrderNumber = (Integer) reportData.get("todayOrderNumber");//今日预约
        Integer thisWeekOrderNumber = (Integer) reportData.get("thisWeekOrderNumber");//本周预约
        Integer thisMonthOrderNumber = (Integer) reportData.get("thisMonthOrderNumber");//本月预约
        Integer todayVisitsNumber = (Integer) reportData.get("todayVisitsNumber");//今日到诊
        Integer thisWeekVisitsNumber = (Integer) reportData.get("thisWeekVisitsNumber");//本周到诊
        Integer thisMonthVisitsNumber = (Integer) reportData.get("thisMonthVisitsNumber");//本月到诊
        List<Map<String, Object>> hotSetmeal = (List<Map<String, Object>>) reportData.get("hotSetmeal");//热门套餐
        //在内存中创建一个Excel文件(绑定模板文件)
        XSSFWorkbook workbook = null;
        try {
            //通过反射资源流的方式, 读取resources下的报表模板
            workbook = new XSSFWorkbook(Resources.getResourceAsStream("report_template.xlsx"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取工作表
        XSSFSheet sheet = workbook.getSheetAt(0);
        // 行数和列数的起始数值都为 0
        //插入第3行数据
        sheet.getRow(2).getCell(5).setCellValue(reportDate);
        //插入第5行数据
        sheet.getRow(4).getCell(5).setCellValue(todayNewMember);
        sheet.getRow(4).getCell(7).setCellValue(totalMember);
        //插入第6行数据
        sheet.getRow(5).getCell(5).setCellValue(thisWeekNewMember);
        sheet.getRow(5).getCell(7).setCellValue(thisMonthNewMember);
        //插入第8行数据
        sheet.getRow(7).getCell(5).setCellValue(todayOrderNumber);
        sheet.getRow(7).getCell(7).setCellValue(todayVisitsNumber);
        //插入第9行数据
        sheet.getRow(8).getCell(5).setCellValue(thisWeekOrderNumber);
        sheet.getRow(8).getCell(7).setCellValue(thisWeekVisitsNumber);
        //插入第10行数据
        sheet.getRow(9).getCell(5).setCellValue(thisMonthOrderNumber);
        sheet.getRow(9).getCell(7).setCellValue(thisMonthVisitsNumber);
        //插入第12行和13行数据
        int num = 12;
        for (Map<String, Object> setmeal : hotSetmeal) {
            String name = (String) setmeal.get("name");
            BigDecimal proportion = (BigDecimal) setmeal.get("proportion");
            Long setmeal_count = (Long) setmeal.get("setmeal_count");
            sheet.getRow(num).getCell(4).setCellValue(name);
            sheet.getRow(num).getCell(5).setCellValue(setmeal_count);
            sheet.getRow(num).getCell(6).setCellValue(proportion.toString());
            num++;
        }
        try {
            //设置以附件形式打开的响应头, 下载的报表名称为report.xls
            response.setContentType("application/vnd.ms-excel;chartset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=report.xls");
            //构建响应输出流对象
            ServletOutputStream out = response.getOutputStream();
            workbook.write(out);
            out.flush();
            out.close();
            workbook.close();
        } catch (IOException e) {
            log.info("下载失败, 请重试");
            e.printStackTrace();
        }
        //返回结果
        return new Result(true, MessageConst.ACTION_SUCCESS);
    }
}
